package com.javaweb.util.core;

import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.io.Serializable;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

import javax.imageio.ImageIO;
import javax.imageio.stream.ImageOutputStream;

import org.apache.catalina.core.ApplicationPart;
import org.apache.tomcat.util.http.fileupload.FileItem;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.apache.tomcat.util.http.fileupload.disk.DiskFileItemFactory;
import org.springframework.http.MediaType;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.multipart.MultipartFile;

import com.javaweb.constant.CommonConstant;
import com.javaweb.enums.FileTypeEnum;
import com.javaweb.util.entity.ImageInfo;

import jakarta.servlet.http.Part;

/**
 * 文件工具类
 * 
 * @author tank2140896
 */
public class FileUtil {
	
	/**
	 * 表单属性名称
	 */
	private static final String FORM_FIELD_NAME = "file";
	
	/**
	 * File转MultipartFile
	 * <p>
	 * 用例：MultipartFile mf = fileToMultipartFile(new File("E:\\1.txt"));
	 * @param file File
	 * @return MultipartFile MultipartFile
	 * @throws Exception 异常
	 */
	public static MultipartFile fileToMultipartFile(File file) throws Exception {
		/** 老版本需要引入commons-fileupload
		<dependency>
		    <groupId>commons-fileupload</groupId>
		    <artifactId>commons-fileupload</artifactId>
		    <version>1.4</version>
		</dependency>
		同时FileItem之类用的也是该包下的org.apache.commons.fileupload.xxx之类
		*/
		FileItem item = new DiskFileItemFactory().createItem(FORM_FIELD_NAME,MediaType.MULTIPART_FORM_DATA_VALUE,true,file.getName());
		try(InputStream inputStream = new FileInputStream(file);
			OutputStream outputStream = item.getOutputStream();) {
			IOUtils.copy(inputStream,outputStream);
		}catch (Exception e) {
			throw new Exception(e);
		}
		Part part = new ApplicationPart(item,file);
		return new StandardMultipartFile(part,file.getName());
	}
	
	/**
	 * InputStream转MultipartFile
	 * <p>
	 * 用例：
	 * InputStream inputStream = new FileInputStream(new File("E:\\1.txt"));
	 * 或
	 * InputStream inputStream = HttpUtil.getURLConnection(downloadUrl).getInputStream();
	 * MultipartFile multipartFile = inputStreamToMultipartFile(inputStream,"E:\\",null,null);
	 * @param inputStream InputStream
	 * @param tempDirPath 临时目录
	 * @param prefix 文件前缀
	 * @param suffix 文件后缀
	 * @return MultipartFile MultipartFile
	 * @throws Exception 异常
	 */
	public static MultipartFile inputStreamToMultipartFile(InputStream inputStream,String tempDirPath,String prefix,String suffix) throws Exception {
		if(prefix==null) {
			prefix = "tmp_"+UUID.randomUUID().toString();
		}
		if(suffix==null) {
			suffix = ".tmp";
		}
		File file = Files.createTempFile(Paths.get(tempDirPath),prefix,suffix).toFile();
		MultipartFile multipartFile = fileToMultipartFile(file);
		file.delete();
		return multipartFile;
	}
	
	public static ByteArrayOutputStream cloneInputStream(InputStream inputStream) throws Exception {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len;
        while ((len = inputStream.read(buffer)) > -1) {
            baos.write(buffer, 0, len);
        }
        baos.flush();
        return baos;
    }
	
	/**
	 * MultipartFile转File
	 * <p>
	 * 用例：File file = multipartFileToFile(multipartFile,"E:\\2.txt");
	 * @param multipartFile MultipartFile
	 * @param filePath 文件路径
	 * @return File File
	 * @throws Exception 异常
	 */
	public static File multipartFileToFile(MultipartFile multipartFile,String filePath) throws Exception {
		File file = new File(filePath);
		multipartFile.transferTo(file);
		return file;
	}
	
	/**
	 * 递归获得某个文件夹下的所有文件夹和文件名称
	 * @param file 文件夹路径
	 * @param fileList 文件对象集合
	 * @param recursion 是否递归（true：是；false：否）
	 * @param showHidden 是否显示隐藏文件（true：是；false：否）
	 * @return List<File> 文件对象集合
	 */
	public static List<File> getAllFilesName(File file,List<File> fileList,boolean recursion,boolean showHidden){
		if(file.isDirectory()){
			File files[] = file.listFiles();
			if(files!=null) {
				for (int i=0;i<files.length;i++) {
					if(showHidden){
						fileList.add(files[i]);
					}else{
						if(!files[i].isHidden()){
							fileList.add(files[i]);
						}
					}
					if(recursion){
						getAllFilesName(files[i],fileList,recursion,showHidden);
					}
				}
			}
		}
		return fileList;
	}
	
    /**
     * 创建文件或文件夹
     * @param file 文件或文件夹路径
     * @param fileTypeEnum FileTypeEnum
     * @throws IOException 输入输出流异常
     */
	public static void makeFileOrFolder(File file,FileTypeEnum fileTypeEnum) throws IOException {
    	if(!file.exists()){
    		switch(fileTypeEnum) {
    			case FILE -> file.createNewFile();//文件
    			case FOLDER -> file.mkdirs();//文件夹
    		}
    	}
    }
    
    /**
     * 剪切文件
     * @param originFilePath 需要剪切的文件路径
     * @param needToFilePath 需要剪切到的文件路径
     * @param buffer 缓冲区
     * @param coverSameNameFile 是否需要覆盖同名文件（true：是；false：否）
     * @throws Exception 异常
     */
	public static void cutFile(String originFilePath,String needToFilePath,byte[] buffer,boolean coverSameNameFile) throws Exception {
    	File originFile = new File(originFilePath);
    	File needToFile = new File(needToFilePath);
    	//String originFileRootPath = originFile.getPath().substring(0,originFile.getPath().lastIndexOf(File.separator)+1);
    	String needToFileRootPath = needToFile.getPath().substring(0,needToFile.getPath().lastIndexOf(File.separator)+1);
    	if(coverSameNameFile){//需要覆盖同名文件
    		if(Objects.equals(originFile.getName(),needToFile.getName())){
    			needToFile.delete();
    		}
    		writeFile(new FileInputStream(originFile),buffer,new File(needToFileRootPath+originFile.getName()));
			originFile.delete();
    	}else{
    		if(!(Objects.equals(originFile.getName(),needToFile.getName()))){
    			writeFile(new FileInputStream(originFile),buffer,new File(needToFileRootPath+originFile.getName()));
    		}
    		originFile.delete();
    	}
    }
    
    //写文件
    public static void writeFile(InputStream inputStream,byte[] buffer,File file) throws IOException {
    	/** 
    	 * 多文件合并写入                  
    	 * FileOutputStream fos = new FileOutputStream(new File("test.zip"));
    	 * fos.write(new byte[1]);
    	 * fos.write(new byte[2]);
    	 * fos.write(new byte[3]);
    	 * fos.close();
    	 */
		try(OutputStream outputStream = new FileOutputStream(file)) {
			int n = 0;
			while ((n=inputStream.read(buffer)) != -1) {
				outputStream.write(buffer,0,n);
			}
			inputStream.close();
		} catch (IOException e) {
			throw new IOException(e);
		}
    }
    
    //写文件
    public static void writeFile(InputStream inputStream,File file) throws IOException {
    	try(OutputStream outputStream = new FileOutputStream(file)) {
    		inputStream.transferTo(outputStream);
    	} catch (IOException e) {
    		throw new IOException(e);
    	}
    }
  	
  	//写文件
  	public static void writeFile(InputStream inputStream,byte[] buffer,Path path) throws IOException {
		try(OutputStream outputStream = Files.newOutputStream(path)) {
			int n= 0;
			while ((n=inputStream.read(buffer)) != -1) {
				outputStream.write(buffer,0,n);
			}
			inputStream.close();
		} catch (IOException e) {
			throw new IOException(e);
		}
  	}
  	
	//下文件
	public static void downloadFile(OutputStream outputStream,byte[] buffer,File file) throws IOException{
		/**
    	 * 多文件内容读取
    	 * FileInputStream fis = new FileInputStream(new File("test.zip"));
    	 * fis.read(new byte[1]);
    	 * fis.read(new byte[2]);
    	 * fis.read(new byte[3]);
    	 * fis.close();
    	 */
		try(InputStream inputStream = new FileInputStream(file)) {
			int n=0;
			while ((n=inputStream.read(buffer)) != -1) {
				outputStream.write(buffer,0,n);
			}
			outputStream.close();
		} catch (IOException e) {
			throw new IOException(e);
		} 
	}
	
	//下文件
	public static void downloadFile(OutputStream outputStream,byte[] buffer,Path path) throws IOException{
		try(InputStream inputStream = Files.newInputStream(path)) {
			int n=0;
			while ((n=inputStream.read(buffer)) != -1) {
				outputStream.write(buffer,0,n);
			}
			outputStream.close();
		} catch (IOException e) {
			throw new IOException(e);
		} 
	}
	
	//下文件
	public static void downloadFile(OutputStream outputStream,byte[] buffer,InputStream inputStream) throws IOException{
		try{
			int n=0;
			while ((n=inputStream.read(buffer)) != -1) {
				outputStream.write(buffer,0,n);
			}
			outputStream.close();
			inputStream.close();
		} catch (IOException e) {
			throw new IOException(e);
		} 
	}
	
	//字节流追加文件并设置编码
	public static void writeFileAppend(File file,String context) throws IOException{
		//字符流
		//Writer out = new FileWriter(f,true);//加true的话,不会替换原来文件的内容,直接追加
 	   	//Reader in = new FileReader(f);
		//try(BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file,true),"UTF-8"))) {
		try(BufferedWriter bufferedWriter = Files.newBufferedWriter(file.toPath(),StandardCharsets.UTF_8,StandardOpenOption.APPEND)) {
			bufferedWriter.write(context);
		} catch (IOException e) {
			throw new IOException(e);
		}
	}
	
	//字节流追加文件并设置编码
	public static void writeFileAppend(Path path,String context) throws IOException{
		//字符流
		//Writer out = new FileWriter(f,true);//加true的话,不会替换原来文件的内容,直接追加
 	   	//Reader in = new FileReader(f);
		//try(BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(path.toFile(),true),"UTF-8"))) {
		try(BufferedWriter bufferedWriter = Files.newBufferedWriter(path,StandardCharsets.UTF_8,StandardOpenOption.APPEND)) {
			bufferedWriter.write(context);
		} catch (IOException e) {
			throw new IOException(e);
		}
	}
	
	//一行一行读取
	public static List<String> readFileLineByLine(File file,List<String> lineList) throws IOException{
		try(LineNumberReader lineNumberReader = new LineNumberReader(new InputStreamReader(new FileInputStream(file),StandardCharsets.UTF_8))) {
			String eachLine = null;
			while((eachLine=lineNumberReader.readLine())!=null){
				lineList.add(eachLine);
			}
		}catch(IOException e){
			throw new IOException(e);
		}
		return lineList;
	}
	
	//序列化输出
	@Deprecated
	public static void writeSerialize(String filePath,Object obj) throws IOException{
		Path path = Paths.get(filePath);
		if(Files.isDirectory(path)){
			return;
		}
		if(!Files.exists(path)){
			Files.createFile(path);
		}
		try(OutputStream bos = new FileOutputStream(new File(filePath));
			ObjectOutputStream oos = new ObjectOutputStream(bos);) {
			oos.writeObject(obj);
		} catch (Exception e) {
			throw new IOException(e);
		}
	}
	
	//序列化读取
	public static Object readSerialize(String filePath) throws IOException,ClassNotFoundException{
		Path path = Paths.get(filePath);
		if(Files.isReadable(path)){
			try(BufferedInputStream bis = new BufferedInputStream(Files.newInputStream(path));
				ObjectInputStream ois = new ObjectInputStream(bis);){
				Object obj = ois.readObject();
				return obj;
			}catch (IOException e) {
				throw new IOException(e);
			}
		}
		return null;
	}
	
	//深克隆
	public static Object deepClone(Object object) throws IOException,ClassNotFoundException {
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		ObjectOutputStream oos = new ObjectOutputStream(baos);
		oos.writeObject(object);
		ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
		ObjectInputStream ois = new ObjectInputStream(bais);
		return ois.readObject();
	}
	
	public static void fileToByteArrayOutputStream(File file) throws IOException {
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len = -1;
        InputStream inputStream = new FileInputStream(file);
        while ((len = inputStream.read(buffer)) != -1 ) {  
            baos.write(buffer, 0, len);  
        }
        baos.flush();
        inputStream.close();
        baos.close();
	}
	
	//文件转字节流
	public static byte[] fileToBytes(String filePath,byte[] buffer) throws IOException{
		//final byte b[] = new byte[1024];
		Path path = Paths.get(filePath);
		try(ByteArrayOutputStream baos = new ByteArrayOutputStream();
			FileInputStream fis = new FileInputStream(path.toFile());){
			int n = 0;
			while((n=fis.read(buffer))!=-1){
				baos.write(buffer,0,n);
			}
			return baos.toByteArray();
		}catch (IOException e) {
			return null;
		}
	}
	
	/**
	 * 获取文件哈希值
	 * <p>最简单的可以直接使用如：DigestUtils.md5Hex(new FileInputStream(path))
	 * <ul>
	 * <li>SHA-256：通用场景（数字证书、密码存储、区块链）</li>
	 * <li>SHA-384：高安全性需求（军事、金融）</li>
	 * <li>SHA-512：需要更长哈希的场景（如文件完整性校验）</li>
	 * <li>SHA512/224：需要兼容224位输出的旧系统</li>
	 * <li>SHA512/256：需要兼容256位输出的旧系统（如替换SHA-256）</li>
	 * <li>SHA3-224/256：高安全性需求且支持新算法的系统（如物联网、抗量子计算场景）</li>
	 * <li>SHA3-384/512：极高安全性需求（政府、机密数据）</li>
	 * </ul>
	 * @param filePath 文件全路径
	 * @param buffer 缓冲区大小
	 * @param algorithm 算法（如：MD5、sha256等）
	 * @return String 哈希值
	 * @throws Exception 异常
	 */
	public static String getFileHash(String filePath,byte[] buffer,String algorithm) throws Exception {
		MessageDigest messageDigest = MessageDigest.getInstance("MD5");//推荐使用sha256
		Path path = Paths.get(filePath);
		try(InputStream inputStream = Files.newInputStream(path)){
			int n = 0;
			while((n=inputStream.read(buffer))!=-1){
				messageDigest.update(buffer,0,n);
			}
			BigInteger bigInt = new BigInteger(1,messageDigest.digest());
			return bigInt.toString(16);
		 }catch(Exception e){
			throw new Exception();
		 }
	}
	
	public static void toZip(OutputStream outputStream,byte buffer[],List<File> files) throws IOException{
		ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream);
		for(int i=0;i<files.size();i++){
			File file = files.get(i);
			zipOutputStream.putNextEntry(new ZipEntry(file.getName()));
			int n=0;
			InputStream inputStream = Files.newInputStream(file.toPath());
			while((n=inputStream.read(buffer))!=-1){
				zipOutputStream.write(buffer,0,n);
			}
			inputStream.close();
		}
		zipOutputStream.close();
		outputStream.close();
	}
	
	/**
	 * try(ZipOutputStream zos = new ZipOutputStream(new FileOutputStream("F:\\1.zip"))){
	 *     File file = new File("F:\\1");
	 *	   toZip(file,file.getName(),zos,new byte[1024]);//文件目录可以写成F:/1或F:\\1
	 * }catch(IOException e){
	 *	   throw new IOException(e);
	 * }
	 */
	//压缩文件或目录
	public static void toZip(File file,String name,ZipOutputStream zos,byte buffer[]) throws IOException {
		if(file.isFile()){//文件
			zos.putNextEntry(new ZipEntry(name));
			int n=0;
			InputStream inputStream = Files.newInputStream(Paths.get(file.getPath()));
			while((n=inputStream.read(buffer))!=-1){
				zos.write(buffer,0,n);
			}
			inputStream.close();
		}else{//目录
			 File files[] = file.listFiles();
			 if(files==null||files.length==0){//空文件夹
				 zos.putNextEntry(new ZipEntry(name+File.separator));
				 zos.closeEntry();
			 }else{//非空
				 for(File f:files){
					 toZip(f,name+File.separator+f.getName(),zos,buffer);
				 }
			 }
		}
	}
	
	/**
	 * try(ZipInputStream zis = new ZipInputStream(new FileInputStream("F:\\1.zip"))){
	 *     unZip("F:\\1",zis,new byte[1024]);
	 * }catch(IOException e){
	 *	   throw new IOException(e);
	 * }
	 */
	//解压文件
	public static void unZip(String unZipRootFilePath,ZipInputStream zis,byte buffer[]) throws IOException {
		ZipEntry zipEntry = null;
		int n=0;
		while((zipEntry=zis.getNextEntry())!=null){
			String filePath = unZipRootFilePath+File.separator+zipEntry.getName();
			String fileFolder = filePath.substring(0,filePath.lastIndexOf(File.separator));
			File file = new File(fileFolder);
			if(!file.exists()){
				file.mkdirs();
			}
			file = new File(filePath);
			if(!file.isDirectory()){
				OutputStream outputStream = Files.newOutputStream(file.toPath());
				while((n=zis.read(buffer))!=-1){
					outputStream.write(buffer,0,n);
				}
				outputStream.close();
			}
		}
	}
	
	//图片转Base64字符串
	public static String imageSrcToBase64String(BufferedImage image) {
	    byte[] data = null;
	    try{
	    	ByteArrayOutputStream baos = new ByteArrayOutputStream();
	    	ImageOutputStream ios = ImageIO.createImageOutputStream(baos);
	    	ImageIO.write(image,"jpeg",ios);
	    	InputStream input = new ByteArrayInputStream(baos.toByteArray());
	    	data = new byte[input.available()];
	    	input.read(data);
	    } catch (IOException e) {
	    	data = null;
	    }
	    if(data==null){
	    	return null;
	    }else{
	    	data = Base64.getEncoder().encode(data);
	    	return new String(data);
	    }
	}
	
	//图片转Base64字符串
	public static String imageSrcToBase64String(String src) {
	    byte[] data = null;
	    try(InputStream inputStream = new FileInputStream(new File(src))) {
	        data = new byte[inputStream.available()];
	        inputStream.read(data);
	    } catch (IOException e) {
	        //do nothing
	    }
	    if(data==null){
	    	return null;
	    }else{
	    	data = Base64.getEncoder().encode(data);
	    	return new String(data);
	    }
	}
	
	//Base64字符串解码
	public static byte[] getBase64Byte(String imageBase64String) {
		try{
			//为了去除data:image/png;base64,
			imageBase64String = imageBase64String.split(",")[1];
		}catch(Exception e){
			//do nothing
		}
		byte[] data = null;
		try{
			data = Base64.getDecoder().decode(imageBase64String.getBytes());
			for(int i=0;i<data.length;++i) {
				if(data[i]<0){
					data[i] += 256;
				}
			}
			//OutputStream out = new FileOutputStream(path);
			//out.write(data);
			//out.close();
		} catch (Exception e){
			//do nothing
		}
		return data;
	}
	
	//按字节读取
	public static List<String> readFileByByte(String fileName,byte number) throws Exception {
		List<String> out = new ArrayList<>();
		RandomAccessFile randomAccessFile = new RandomAccessFile(fileName,"r");
		long position = 0;
		List<Byte> list = new ArrayList<>();
		while(true){
			try{
				randomAccessFile.seek(position++);
				byte[] bytes = new byte[1];
				bytes[0] = randomAccessFile.readByte();
				list.add(bytes[0]);
				if(bytes[0]==number){//例如125=}
					byte b[] = new byte[list.size()];
					for(int i=0;i<list.size();i++){
						b[i] = list.get(i);
					}
					out.add(new String(b,StandardCharsets.UTF_8));
					list = new ArrayList<>();
				}
			}catch(Exception e){
				break;
			}
		}
		randomAccessFile.close();
		return out;
	}
	
	//按行数读取（空行也算的）
	public static String readFileByLineNumber(String filePath,long lineNumber) throws Exception {
	    return Files.lines(Paths.get(filePath),StandardCharsets.UTF_8).skip(lineNumber-1).limit(1).iterator().next();
	}
	
	//获取总行数（空行也算的）
	public static long getFileAllLines(String filePath) throws Exception {
	    return Files.lines(Paths.get(filePath),StandardCharsets.UTF_8).count();
	}
	
	//读取某一行数据并修改该行数据（Scanner scanner = new Scanner(file)也能读取）
	@Deprecated
    public static void readAndModifyFile(String fileName,String newFileName,long lineNumber,String context) throws Exception {
        try(LineNumberReader lineNumberReader = new LineNumberReader(new InputStreamReader(new FileInputStream(fileName),StandardCharsets.UTF_8))) {
            String eachLine = null;
            long position = 1;
            while((eachLine=lineNumberReader.readLine())!=null){
                if(lineNumber==position) {
                    eachLine = context;
                }
                writeFileAppend(Paths.get(newFileName),eachLine+(SystemUtil.isLinux()?CommonConstant.ENTER_LINUX:CommonConstant.ENTER_WINDOWS));
                position++;
            }
        }catch(IOException e){
            throw new IOException(e);
        }
    }
	
	//旋转图片（更多图片操作参考：Thumbnailator）
	public static BufferedImage rotateImage(final BufferedImage bufferedimage,final int degree){
		int src_width = bufferedimage.getWidth(null);
        int src_height = bufferedimage.getHeight(null);
        //计算旋转后图片的尺寸
        Rectangle rect_des = calcRotatedSize(new Rectangle(new Dimension(src_width,src_height)),degree);
        BufferedImage res = new BufferedImage(rect_des.width,rect_des.height,BufferedImage.TYPE_INT_RGB);
        Graphics2D g2 = res.createGraphics();
        //进行转换
        g2.translate((rect_des.width-src_width)/2,(rect_des.height-src_height)/2);
        g2.rotate(Math.toRadians(degree),src_width/2,src_height/2);
        g2.drawImage(bufferedimage,null,null);
        return res;
    }
	
	//计算旋转尺寸（更多图片操作参考：Thumbnailator）
	public static Rectangle calcRotatedSize(Rectangle src,int angel) {
        //如果旋转的角度大于90度做相应的转换
        if(angel>=90){
            if(angel/90%2==1){
                int temp = src.height;
                src.height = src.width;
                src.width = temp;
            }
            angel = angel%90;
        }
        double r = Math.sqrt(src.height*src.height+src.width*src.width)/2;
        double len = 2*Math.sin(Math.toRadians(angel)/2)*r;
        double angel_alpha = (Math.PI-Math.toRadians(angel))/2;
        double angel_dalta_width = Math.atan((double)src.height/src.width);
        double angel_dalta_height = Math.atan((double)src.width/src.height);
        int len_dalta_width = (int)(len*Math.cos(Math.PI-angel_alpha-angel_dalta_width));
        int len_dalta_height = (int)(len * Math.cos(Math.PI-angel_alpha-angel_dalta_height));
        int des_width = src.width+len_dalta_width*2;
        int des_height = src.height+len_dalta_height*2;
        return new Rectangle(new Dimension(des_width,des_height));
    }
	
	//图片转字节（format如png）（更多图片操作参考：Thumbnailator）
	public static byte[] imageToBytes(BufferedImage bufferedImage,String format) throws Exception {
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		ImageIO.write(bufferedImage,format,baos);
		return baos.toByteArray();
	}
	
	//获取图片信息（更多图片操作参考：Thumbnailator）
	public static ImageInfo getImageInfo(File file) throws Exception {
		ImageInfo imageInfo = new ImageInfo();
		BufferedImage bufferedImage = ImageIO.read(new FileInputStream(file)); 
		imageInfo.setFileSize(String.format("%.1f",file.length()/1024.0));//图片大小
		imageInfo.setWidth(String.valueOf(bufferedImage.getWidth()));//图片宽度
		imageInfo.setHeight(String.valueOf(bufferedImage.getHeight()));//图片高度
		//还可以获得其他属性
		return imageInfo;
	}
	
}

/* -------------------------------------------------- 分界线 -------------------------------------------------- */

/**
 * StandardMultipartFile
 * @author tank2140896
 * 拷贝org.springframework.web.multipart.support.StandardMultipartHttpServletRequest类里的静态内部类StandardMultipartFile
 */
class StandardMultipartFile implements MultipartFile, Serializable {

	private static final long serialVersionUID = 1L;

	private final Part part;

	private final String filename;

	public StandardMultipartFile(Part part, String filename) {
		this.part = part;
		this.filename = filename;
	}

	@Override
	public String getName() {
		return this.part.getName();
	}

	@Override
	public String getOriginalFilename() {
		return this.filename;
	}

	@Override
	public String getContentType() {
		return this.part.getContentType();
	}

	@Override
	public boolean isEmpty() {
		return (this.part.getSize() == 0);
	}

	@Override
	public long getSize() {
		return this.part.getSize();
	}

	@Override
	public byte[] getBytes() throws IOException {
		return FileCopyUtils.copyToByteArray(this.part.getInputStream());
	}

	@Override
	public InputStream getInputStream() throws IOException {
		return this.part.getInputStream();
	}

	@Override
	public void transferTo(File dest) throws IOException, IllegalStateException {
		this.part.write(dest.getPath());
		if (dest.isAbsolute() && !dest.exists()) {
			// Servlet Part.write is not guaranteed to support absolute file paths:
			// may translate the given path to a relative location within a temp dir
			// (e.g. on Jetty whereas Tomcat and Undertow detect absolute paths).
			// At least we offloaded the file from memory storage; it'll get deleted
			// from the temp dir eventually in any case. And for our user's purposes,
			// we can manually copy it to the requested location as a fallback.
			FileCopyUtils.copy(this.part.getInputStream(), Files.newOutputStream(dest.toPath()));
		}
	}

	@Override
	public void transferTo(Path dest) throws IOException, IllegalStateException {
		FileCopyUtils.copy(this.part.getInputStream(), Files.newOutputStream(dest));
	}
	
}
